#include <math.h>
#include "databank.h"
#include "sprite.h"
#include "weapon.h"
#include "player.h"
#include "shot.h"

// For weapons who do not process anything post-weapon
bool doFireIdle(Weapon *wp, Player *pl, double delta) { return true; }

// Spends ammo, returns true if shot to be fired
bool useAmmo(Player *pl) {
    if (pl->curWeapon()->ammo > 0) {
        pl->curWeapon()->ammo--;
        return true;
    } else {
        return false;
    }
}

// X/Y -> Ang/r
double *cartToPol(double *v)
{
    double rad,spd;
    rad = atan2(-v[1],v[0]);
    spd = sqrt(v[0]*v[0]+v[1]*v[1]);

    v[0] = rad;
    v[1] = spd;

    return v;
}

// Ang/r -> X/Y
double *polToCart(double *v)
{
    double x,y;

    x = cos(v[0])*v[1];
    y =-sin(v[0])*v[1];

    v[0] = x;
    v[1] = y;

    return v;
}


Weapon::Weapon(DataBank *d, WeaponType t)
{
    // Add new shottype pointers here when needed
    data = d;
    switch(t) {
        case WEAPON_GUN:
            bmp = d->sprites->get_weapon("gun.bmp");
            fire = W_Gun::fire;
            doFire = W_Gun::doFire;
            ammo = 100;
            break;

        case WEAPON_LASER:
            bmp = d->sprites->get_weapon("laser.bmp");
            fire = W_Laser::fire;
            doFire = doFireIdle;
            ammo = 3;
            break;

        case WEAPON_BADGER:
            bmp = d->sprites->get_weapon("badger.bmp");
            fire = W_Badger::fire;
            doFire = doFireIdle;
            ammo = 10;
            break;

        case WEAPON_CARPET:
            bmp = d->sprites->get_weapon("badgerstorm.bmp");
            fire = W_Carpet::fire;
            doFire = doFireIdle;
            ammo = 3;
            break;

        case WEAPON_PLANETC:
            bmp = d->sprites->get_weapon("planetc.bmp");
            fire = W_PlanetCreator::fire;
            doFire = doFireIdle;
            ammo = 3;
            break;

        case WEAPON_CLUSTER:
            bmp = d->sprites->get_weapon("cluster.bmp");
            fire = W_Cluster::fire;
            doFire = doFireIdle;
            ammo = 10;
            break;

        case WEAPON_PANZERSCHRECK:
            bmp = d->sprites->get_weapon("panzerschrek.bmp");
            fire = W_Panzerschreck::fire;
            doFire = W_Panzerschreck::doFire;
            ammo = 3;
            break;

        case WEAPON_BIGBANG:
            bmp = d->sprites->get_weapon("bigbang.bmp");
            fire = W_BigBang::fire;
            doFire = doFireIdle;
            ammo = 1;
    }
}

Shot *W_Gun::fire(Player *player, DataBank *data, double *pos, double *vel) 
{
    Weapon *wp = player->curWeapon();
    if(useAmmo(player)) {
        wp->timer = 0.0; // Repeat for 10 seconds
        wp->arg1 = 5;
        wp->arg_pos[0] = pos[0]; wp->arg_pos[1] = pos[1];
        wp->arg_vel[0] = vel[0]; wp->arg_vel[1] = vel[1];
        return(data->makeShot(new Shot(data, SHOT_GUN, pos, vel)));
    } else return NULL;
}

bool W_Gun::doFire(Weapon *wp, Player *pl, double delta)
{
    wp->timer+=delta;
    while(wp->timer >= 0.2) {
        double vel[2];
        vel[0] = wp->arg_vel[0];
        vel[1] = wp->arg_vel[1];
        cartToPol(vel);
        vel[0] = vel[0]-(PIE/18.0)+frand()*(PIE/18.0*2.0);
        polToCart(vel);

        wp->data->makeShot(new Shot(wp->data, SHOT_GUN, wp->arg_pos, vel));
        wp->timer -= 0.2;
        wp->arg1--;
        if(wp->arg1 <= 0) break;
    }

    if(wp->arg1 <= 0) return true;
    else return false;
}

Shot *W_Laser::fire(Player *player, DataBank *data, double *pos,
        double *vel)
{
    if(useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_LASER, pos, vel)));
    /*
       for (int x=0; x<SCREEN_W; x += 10) {
       for (int y=0; y<SCREEN_H; y += 10) {
       double pos[2] = {x, y};
       double vel[2] = {0.0, 0.0};
       data->makeParticle(pos, vel, makecol(255,255,255));
       }
       }
       */
    else return NULL;
}

Shot *W_Badger::fire(Player *player, DataBank *data, double *pos,
        double *vel)
{
    if(useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_BADGER, pos, vel)));
    else return NULL;
}

Shot *W_Carpet::fire(Player *player, DataBank *data, double *pos,
        double *vel)
{
    if(useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_CARPET, pos, vel)));
    else return NULL;
}

Shot *W_PlanetCreator::fire(Player *player, DataBank *data, double *pos
        , double *vel) {
    if (useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_PLANETMAKER, pos, vel)));
    else return NULL;
}

Shot *W_Cluster::fire(Player *player, DataBank *data, double *pos,
        double *vel)
{
    if(useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_CLUSTER, pos, vel)));
    else return NULL;
}

Shot *W_Panzerschreck::fire(Player *player, DataBank *data, double *pos,
        double *vel)
{
    Weapon *wp = player->curWeapon();
    if(useAmmo(player)) {
        wp->timer = 0.0; // Repeat for 10 seconds
        wp->arg1 = 20;
        wp->arg_pos[0] = pos[0]; wp->arg_pos[1] = pos[1];
        wp->arg_vel[0] = vel[0]; wp->arg_vel[1] = vel[1];
        return(data->makeShot(new Shot(data, SHOT_PANZERSCHRECK, pos,
                        vel)));
    } else return NULL;
}

bool W_Panzerschreck::doFire(Weapon *wp, Player *pl, double delta)
{
    wp->timer+=delta;
    while(wp->timer >= 0.05) {
        double vel[2];
        vel[0] = wp->arg_vel[0];
        vel[1] = wp->arg_vel[1];

        wp->data->makeShot(new Shot(wp->data, SHOT_PANZERSCHRECK,
                    wp->arg_pos, vel));
        wp->timer -= 0.05;
        wp->arg1--;
        if(wp->arg1 <= 0) break;
    }

    if(wp->arg1 <= 0) return true;
    else return false;
}

Shot *W_BigBang::fire(Player *player, DataBank *data, double *pos,
        double *vel) 
{
    if(useAmmo(player))
        return(data->makeShot(new Shot(data, SHOT_BIGBANG, pos, vel)));
    else return NULL;
}
